package com.zte.claa.inficombo.csa.app.a.simulator;

import java.io.BufferedReader;
import java.io.FileReader;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import com.zte.claa.inficombo.csa.app.comm.csif.CSIFCmdBuilder;
import com.zte.claa.inficombo.csa.app.comm.csif.CSIFMessageBuilder;
import com.zte.claa.inficombo.csa.app.comm.csif.mina.CSIFMsgCodecFactory;
import com.zte.claa.inficombo.csa.app.comm.csif.mina.CSIFMsgDecoder;
import com.zte.claa.inficombo.csa.app.comm.csif.mina.CSIFMsgEncoder;
import com.zte.claa.inficombo.csa.app.comm.csif.mina.msg.CSIFMessage;
import com.zte.claa.inficombo.csa.app.config.CSIFSimulatorProps;
import com.zte.claa.inficombo.csa.app.service.jsplugin.JSParam;
import com.zte.claa.inficombo.csa.app.util.SecurityUtil;

@Service("CSIFSimulator")
@Lazy(false)
public class CSIFSimulator implements InitializingBean, DisposableBean  {
	private  Logger logger = LoggerFactory.getLogger(CSIFSimulator.class);

	@Autowired
	private CSIFSimulatorProps config;
	
	// 
	private IoAcceptor acceptor = null;
	
	// 模拟数据发送线程池.
    private ExecutorService execSvr;
	
	/**
	 * 启动监听。
	 */
	public void start() {
		if (this.config.getIsstart().trim().equalsIgnoreCase("N")) {
			logger.info("The CSIFSimulator is configured NOT start!");
			return;
		}
		try {
			this.execSvr = Executors.newFixedThreadPool(1);
			this.acceptor = new NioSocketAcceptor();
			acceptor.getFilterChain().addLast("logger", new LoggingFilter());
			// 实例化编解码器。
			CSIFMsgDecoder decoder = new CSIFMsgDecoder(Charset.forName(this.config.getCharsetname()));
			CSIFMsgEncoder encoder = new CSIFMsgEncoder(Charset.forName(this.config.getCharsetname()));
			CSIFMsgCodecFactory codecFactory = new CSIFMsgCodecFactory(decoder, encoder);
			// 添加到过滤链。
			this.acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(codecFactory));
			this.acceptor.setHandler(new CSIFSimulatorHandler(this));
			this.acceptor.getSessionConfig().setReadBufferSize(this.config.getRedabufsize());
			this.acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60);
			this.acceptor.bind(new InetSocketAddress(this.config.getPort()));
			logger.error("CSIFSimulator starts OK and listen at port: " + this.config.getPort());
		} catch (Exception e) {
			logger.error("CSIFSimulator starts failed: " + e.getMessage(), e);
		}
	}

	@Override
	public void destroy() throws Exception {
		if(this.execSvr != null){
			this.execSvr.shutdown();
			this.execSvr = null;
		}
		if(this.acceptor != null){
			this.acceptor.unbind();
			this.acceptor.dispose();
			this.acceptor = null;
		}		
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.start();
	}	
	
	/**
	 * 
	 * @param session
	 */
	public void receiveNewSession(IoSession session){
		this.execSvr.submit(new Runnable(){
			@Override
			public void run() {
				try {
					sendRptData(session);
				}catch(Exception e){
					logger.error("sendRptData failed: session="+session.getId(), e);
				}
			}
		});
	}
	
	/**
	 * 发送模拟数据
	 * 
	 * @param session
	 */
	public void sendRptData(IoSession session){
		List<String> dataList = this.config.getRptdata();
		if(dataList == null || dataList.size() == 0){
			logger.info("There is no data to be reported!");
			return;
		}
		int cc = 0;
		int totalNum = this.config.getRpttotalnum();
		while(cc < totalNum){
			cc++;
			for(String confData : dataList){
				String jsonData = this.genJsonData(confData);
				CSIFMessage csifMsg = CSIFMessageBuilder.buildMessage(jsonData);
				session.write(csifMsg);
				logger.info("Send data: "+jsonData);
			}
			try{
				Thread.sleep(this.config.getRptcirclesecond()*1000L);
			}catch(Exception ignore){}
		}
	}
	
	/**
	 * 构造上报数据json字符串
	 * 
	 * {
		    "cmd": "updata", 
		    "deveui": "2C26C50001FF0001",   ---->hex-->byte[], --Base64编码.  CSIFCmdBuilder.base64Encode
		    "payload": "xxxxx",
			"port": 21
		}
		
		@param configData=4a770065650001:AA0122334455667788990099887766
	 */
	private String genJsonData(String configData) {
		JSONObject json = new JSONObject();		
		try {
			json.put("cmd", "updata");
			String[] arr = configData.trim().split(":");
			String devEui = arr[0].toLowerCase();
			byte[] bs = SecurityUtil.parseHexStr2Byte(arr[1]);
			String payload = CSIFCmdBuilder.base64Encode(bs);
			json.put("deveui", devEui);
			json.put("port", 20);
			json.put("payload", payload);
		} catch (Exception e) {
			logger.error("genJsonData failed: " + configData, e);
		}
		return json.toString();
	}
	
	// just for test
	public static void main2(String[] args){
		if(true){
			StringBuffer jsbuf = new StringBuffer();
			jsbuf.append("var a = null; ");
			jsbuf.append("var b = true; ");
			jsbuf.append("var c = null; ");
			jsbuf.append("(a || b) || c ");
			ScriptEngine jsEngine = new ScriptEngineManager().getEngineByName("nashorn");
			try {
				Object o = jsEngine.eval(jsbuf.toString());
				System.out.println("ret="+o);
			} catch (ScriptException e) {
				e.printStackTrace();
			}
			return;
		}
		try {
			String str = "AA012233060001001D001C002B002B0A28802B001D000100010320FCF901230150FF";
			System.out.println("src1: "+str);
			byte[] bs = SecurityUtil.parseHexStr2Byte(str);
			for(int i=0; i<bs.length; i++){
				System.out.print("bs["+i+"]="+bs[i]+", ");
			}
			System.out.println("");
			String payload = CSIFCmdBuilder.base64Encode(bs);
			System.out.println("payload1: "+payload);
			bs = payload.getBytes("utf-8");
			for(int i=0; i<bs.length; i++){
				System.out.print("bs["+i+"]="+bs[i]+", ");
			}
			System.out.println("");
			System.out.println("payload2: "+payload);
			bs = CSIFCmdBuilder.base64Decode(payload);
			for(int i=0; i<bs.length; i++){
				System.out.print("bs["+i+"]="+bs[i]+", ");
			}
			System.out.println("");
			System.out.println("src2: "+SecurityUtil.parseByte2HexStr(bs));
			
			ScriptEngine jsEngine = new ScriptEngineManager().getEngineByName("nashorn");
			String filePath = "D:\\eclipse_wp\\project_Inficombov2_csa\\src\\main\\resources\\js\\plugin\\shichuang_trapdoor.js";
			jsEngine.eval(new BufferedReader(new FileReader(filePath)));
			Invocable jsRunner = (Invocable) jsEngine;
			JSParam jsParam = new JSParam();
			jsParam.appendPara("circle", "60");
			bs = (byte[])jsRunner.invokeFunction("SetHBCircle", jsParam);
			System.out.println("-------------SetHBCircle---------- ");
			for(int i=0; i<bs.length; i++){
				System.out.print("bs["+i+"]="+bs[i]+", ");
			}
			System.out.println("");
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
	}
	
}
